package walletuserslogic

import (
	"context"
	"go.uber.org/zap"
	"navi-mumbai/app/rpc/model/pg/wallet"
	"navi-mumbai/common/key/dbkey"
	"navi-mumbai/common/key/walletkey"
	"navi-mumbai/common/uniqueid"
	"navi-mumbai/common/utils"
	"navi-mumbai/common/xerr"
	"time"

	"github.com/shopspring/decimal"

	"navi-mumbai/app/rpc/wallet/internal/svc"
	"navi-mumbai/app/rpc/wallet/pb"

	"github.com/zeromicro/go-zero/core/logx"
)

type CreateUserDepositLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewCreateUserDepositLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateUserDepositLogic {
	return &CreateUserDepositLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

// 创建用户充值流水
func (l *CreateUserDepositLogic) CreateUserDeposit(in *pb.CreateUserDepositReq) (*pb.CreateUserDepositResp, error) {
	defer utils.RecoverPanic()

	// 校验是否存在正在进行的充值
	var err error
	var count int64
	s1 := time.Now().Add(-time.Minute * 15)
	e1 := time.Now()
	count, err = l.svcCtx.UserDepositFlowModel.Count(l.ctx, in.Uid, []int64{walletkey.DepositFlowStateWait}, in.MoneyType, in.CurrencyType, in.PayChannelId, &s1, &e1)
	if err != nil {
		l.Logger.Errorf("err == ", zap.Error(err))
		return nil, xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
	}

	if count > walletkey.MaxProcessingDepositFlowCnt {
		l.Logger.Errorf("err == ", zap.Error(xerr.NewGrpcErrCodeMsg(xerr.RequestParamError, "system is busy, please try again later")))
		return nil, xerr.NewGrpcErrCodeMsg(xerr.RequestParamError, "system is busy, please try again later")
	}

	var dCurrencyAmount decimal.Decimal
	var dMoneyAmount decimal.Decimal
	dCurrencyAmount, err = decimal.NewFromString(in.CurrencyAmount)
	if err != nil {
		l.Logger.Errorf("err == ", zap.Error(err))
		return nil, xerr.NewGrpcErrCodeMsg(xerr.RequestParamError, err.Error())
	}

	// 查询兑换比例
	var cfg *wallet.CurrencyExchangeConfig
	if in.IsInput == dbkey.Enable { // 任意金额
		// 查询币种配置
		var wmc *wallet.PayChannelConfig
		wmc, err = l.svcCtx.PayChannelConfigModel.FindOne(l.ctx, in.PayChannelId)
		if err != nil {
			l.Logger.Errorf("err == ", zap.Error(err))
			if err == wallet.ErrNotFound {
				return nil, xerr.NewGrpcErrCodeMsg(xerr.RequestParamError, "not find pay channel config")
			}
			return nil, xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
		}

		// 判断充值金额是否超过最小最大限制
		dMax := decimal.NewFromInt(wmc.MaxCurrencyAmount)
		dMin := decimal.NewFromInt(wmc.MinCurrencyAmount)
		if dCurrencyAmount.GreaterThan(dMax) || dCurrencyAmount.LessThan(dMin) {
			l.Logger.Errorf("err == ", zap.Error(xerr.NewGrpcErrCodeMsg(xerr.WalletDepositAmountError, "currency amount out of range")))
			return nil, xerr.NewGrpcErrCodeMsg(xerr.WalletDepositAmountError, "currency amount out of range")
		}

		cfg, err = l.svcCtx.CurrencyExchangeConfigModel.FindConfig(l.ctx, in.MoneyType, 0, in.CurrencyType, 1, in.PayChannelId)
		if err != nil {
			l.Logger.Errorf("err == ", zap.Error(err))
			if err == wallet.ErrNotFound {
				return nil, xerr.NewGrpcErrCodeMsg(xerr.RequestParamError, "not find config")
			}
			return nil, xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
		}
		// 计算需要充值金额
		var dCfgMoneyAmount = decimal.NewFromInt(cfg.MoneyAmount)
		dMoneyAmount = dCurrencyAmount.Mul(dCfgMoneyAmount).Round(2)
	} else { // 固定金额
		cfg, err = l.svcCtx.CurrencyExchangeConfigModel.FindConfig(l.ctx, in.MoneyType, 0, in.CurrencyType, dCurrencyAmount.IntPart(), in.PayChannelId)
		if err != nil {
			l.Logger.Errorf("err == ", zap.Error(err))
			return nil, xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
		}
		dMoneyAmount = decimal.NewFromInt(cfg.MoneyAmount)
	}

	//
	var iMoneyAmount int64
	var iCurrencyAmount int64
	iMoneyAmount = dMoneyAmount.Mul(decimal.NewFromInt(100)).RoundFloor(0).IntPart()
	iCurrencyAmount = dCurrencyAmount.Mul(decimal.NewFromInt(100)).RoundFloor(0).IntPart()

	// 创建充值流水
	df := wallet.UserDepositFlow{
		Uid:            in.Uid,
		FlowNo:         uniqueid.GenFlowNoX(),
		MoneyType:      in.MoneyType,
		MoneyAmount:    iMoneyAmount,
		CurrencyType:   in.CurrencyType,
		CurrencyAmount: iCurrencyAmount,
		State:          walletkey.DepositFlowStateInit,
		PayChannelId:   in.PayChannelId,
		PayAccount:     in.PayAccount,
		PayAccountType: in.AccountType,
	}

	// 创建充值流水
	_, err = l.svcCtx.UserDepositFlowModel.Insert(l.ctx, &df)
	if err != nil {
		l.Logger.Errorf("err == ", zap.Error(err))
		return nil, xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
	}
	var resp pb.CreateUserDepositResp
	resp.FlowNo = df.FlowNo
	return &resp, nil
}
